﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;

namespace Taste
{
    public class CodeFileGen
    {
        private string TAB = "\t";
        private StringBuilder code;
        private StringBuilder data;
        private string _OutputFileName = "temp.asm";

        /// <summary>
        /// Starts a new file with the header.
        /// </summary>
        /// <param name="OutputFileName">The file name to the asm.</param>
        /// <param name="SourceFileName">The source file</param>
        public CodeFileGen(string OutputFileName, string SourceFileName)
        {
            code = new StringBuilder();
            Header(OutputFileName, SourceFileName);
            code.AppendLine(TAB + ".text");

            data = new StringBuilder(TAB + ".data");
            data.AppendLine();

        }

        private void Header(string OutputFileName, string SourceFileName)
        {
            _OutputFileName = OutputFileName;
            code.AppendLine("# " + OutputFileName + TAB + TAB + ": MIPS assembly program generated by TasteMIPS v1.0");
            code.AppendLine("# Source file " + TAB + TAB + ": " + SourceFileName);
            code.AppendLine("# Generated time" + TAB + ": " + DateTime.Now.ToString("G"));
        }

        public void AddComment(string Comment)
        {
            code.AppendLine(TAB + "# " + Comment);
        }

        /// <summary>
        /// Adds a new command to the code file.
        /// ex. lw  $t1, 4($fp)
        /// to do a command such as 'syscall' just pass String.Empty or null for the Params.
        /// </summary>
        /// <param name="Cmd">the codeword</param>
        /// <param name="Params">all of the parameters in a string</param>
        public void AddCommand(string Cmd, string Params)
        {
            code.Append(TAB + Cmd);
            if (String.IsNullOrEmpty(Params))
            {
                AddBlankLine();
            }
            else
            {
                code.AppendLine(TAB + Params);
            }
        }

        /// <summary>
        /// Writes the function name to the code file.
        /// </summary>
        /// <param name="FuncName">just the function name</param>
        public void AddFuncName(string FuncName)
        {
            code.AppendLine(FuncName + ":");
        }

        /// <summary>
        /// Writes an empty line to the code block area
        /// </summary>
        public void AddBlankLine()
        {
            code.AppendLine();
        }

        public enum DataType
        {
            ASCIIZ,
            WORD
        }

        /// <summary>
        /// Adds a data constant to the data section
        /// </summary>
        /// <param name="DataName">Name for the constant as read by the code</param>
        /// <param name="Type">the DataType: ASCII or NUM etc</param>
        /// <param name="DataConst">The value of the constant</param>
        public void AddDataConst(string DataName, DataType Type, string DataConst)
        {
            data.Append(DataName + ": " + TAB);
            switch (Type)
            {
                case DataType.ASCIIZ:
                    data.Append(" .asciiz ");
                    data.AppendLine(TAB + " \"" + DataConst + "\"");
                    break;
                case DataType.WORD:
                    data.Append(" .word ");
                    data.AppendLine(TAB + DataConst);
                    break;
            }
        }

        /// <summary>
        /// Writes the code and data to a file.
        /// </summary>
        public void ToFile()
        {
            StreamWriter file = new StreamWriter(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)+ @"/" + _OutputFileName);
            file.WriteLine(code.ToString());
            file.WriteLine(data.ToString());
            file.Close();
        }
    }
}
